package git.bds.nyc.applet.api.service.order.handler;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import git.bds.nyc.applet.api.convert.OrderConvert;
import git.bds.nyc.applet.api.model.dto.OrderAgreeDTO;
import git.bds.nyc.applet.api.model.dto.OrderRefuseDTO;
import git.bds.nyc.communal.mapper.mp.AddressMapper;
import git.bds.nyc.communal.mapper.mp.ContractOrderMapper;
import git.bds.nyc.communal.model.domain.Address;
import git.bds.nyc.communal.model.domain.ContractOrder;
import git.bds.nyc.communal.model.dto.OrderDataDTO;
import git.bds.nyc.communal.util.Base64Util;
import git.bds.nyc.constant.Constants;
import git.bds.nyc.enums.OrderType;
import git.bds.nyc.exception.BusinessException;
import git.bds.nyc.framework.file.minio.MinioConfig;
import git.bds.nyc.framework.file.minio.MinioUtil;
import git.bds.nyc.itext.PDFUtils;
import git.bds.nyc.itext.PdfData;
import git.bds.nyc.page.PageParam;
import git.bds.nyc.page.PageResult;
import git.bds.nyc.result.ResultCode;
import git.bds.nyc.util.DecimalUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 成大事
 * @since 2023/3/12 16:52
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class OrderHandlerServiceImpl implements OrderHandlerService{

    private final AddressMapper addressMapper;

    private final ContractOrderMapper contractOrderMapper;

    private final MinioConfig minioConfig;

    private final MinioUtil minioUtil;

    /**
     * 获取订单页面
     *
     * @param pageParam 页面参数
     * @param type      类型
     * @return {@link PageResult}<{@link ContractOrder}>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public PageResult<ContractOrder> getOrderPageByType(PageParam pageParam, int type) {
        Page<ContractOrder> page = contractOrderMapper.selectPage(new Page<>(pageParam.getPageNo(), pageParam.getPageSize()),
                new LambdaQueryWrapper<ContractOrder>()
                        .select(
                                ContractOrder::getId,
                                ContractOrder::getProductId,
                                ContractOrder::getProductSpecies,
                                ContractOrder::getProductVariety,
                                ContractOrder::getProductCover,
                                ContractOrder::getUnitPrice,
                                ContractOrder::getOrderWeight,
                                ContractOrder::getCreateTime,
                                ContractOrder::getOrderStatus,
                                ContractOrder::getType
                        )
                        .eq(ContractOrder::getSellerId, StpUtil.getLoginIdAsLong())
                        .eq(ContractOrder::getOrderStatus, type)
                        .orderByAsc(ContractOrder::getCreateTime));
        return new PageResult<>(page.getRecords(),page.getTotal());
    }

    /**
     * 获取各种订单数量
     *
     * @return {@link OrderDataDTO}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderDataDTO getQuantitiesOfVariousOrders() {
        long userId = StpUtil.getLoginIdAsLong();
        List<Map<String, Object>> maps = contractOrderMapper.selectMaps(new QueryWrapper<ContractOrder>()
                .select("count(*) as nums,order_status")
                .eq(ContractOrder.SELLER_ID, userId)
                .groupBy(ContractOrder.ORDER_STATUS));
        OrderDataDTO orderDataDTO = new OrderDataDTO();
        for (Map<String, Object> map : maps) {
            log.info(""+map);
            if(ObjectUtil.equal(map.get("orderStatus"), OrderType.UNSIGNED.getValue())){
                orderDataDTO.setUnSigned(Integer.parseInt(map.get("nums").toString()));
                log.info("-UNSIGNED----"+ map.get("nums")+ Integer.parseInt(map.get("nums").toString()));
            }
            if(ObjectUtil.equal(map.get("orderStatus"),OrderType.SIGNED.getValue())){
                orderDataDTO.setSigned(Integer.parseInt(map.get("nums").toString()));
                log.info("-SIGNED----"  + map.get("nums")+ Integer.parseInt(map.get("nums").toString()));
            }
            if(ObjectUtil.equal(map.get("orderStatus"),OrderType.REFUSE_TO_SIGN.getValue())){
                orderDataDTO.setRefuseToSign(Integer.parseInt(map.get("nums").toString()));
                log.info("-REFUSE_TO_SIGN----"+ map.get("nums") + Integer.parseInt(map.get("nums").toString()));
            }
            if(ObjectUtil.equal(map.get("orderStatus"),OrderType.SUCCESSFUL_TRADE.getValue())){
                orderDataDTO.setSuccessfulTrade(Integer.parseInt(map.get("nums").toString()));
                log.info("-SUCCESSFUL_TRADE----"+ map.get("nums")+ Integer.parseInt(map.get("nums").toString()));
            }
        }
        log.info(""+maps);
        return orderDataDTO;
    }


    /**
     * 按id获取订单信息
     *
     * @param id 订单id
     * @return {@link ContractOrder}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContractOrder getOrderInfoById(Long id) {
        return contractOrderMapper.selectOne(new QueryWrapper<ContractOrder>()
                .select(ContractOrder.class,
                        i->!i.getColumn().equals(ContractOrder.ID))
                .eq(ContractOrder.ID,id));
    }

    /**
     * 按id删除订单
     *
     * @param type 类型
     * @param id   身份证件
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delOrderById(int type, Long id) {
        ContractOrder contractOrder = contractOrderMapper.selectOne(new LambdaQueryWrapper<ContractOrder>()
                .select(ContractOrder::getContractUrl,ContractOrder::getBuyerSignature,ContractOrder::getSellerSignature)
                .eq(ContractOrder::getId, id)
                .eq(ContractOrder::getOrderStatus, type));
        if(contractOrder == null){
            throw new BusinessException(ResultCode.NOT_EXIST.getCode(),ResultCode.NOT_EXIST.getMessage());
        }
        List<String> imgList = Arrays.asList(contractOrder.getBuyerSignature(), contractOrder.getSellerSignature(), contractOrder.getContractUrl());
        minioUtil.removeFiles(minioConfig.getBucketName(),imgList);
        return contractOrder.deleteById(id);
    }

    /**
     * 按id拒绝订单
     *
     * @param orderRefuseDTO 订单失败dto
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean refuseOrderById(OrderRefuseDTO orderRefuseDTO) {
        long userId = StpUtil.getLoginIdAsLong();
        return contractOrderMapper.update(null,new LambdaUpdateWrapper<ContractOrder>()
                .set(ContractOrder::getOrderStatus,OrderType.REFUSE_TO_SIGN.getValue())
                .set(ContractOrder::getFailFeedback,orderRefuseDTO.getFeedBack())
                .eq(ContractOrder::getSellerId,userId)
                .eq(ContractOrder::getId, orderRefuseDTO.getId())) > 0;

    }

    /**
     * 按id同意订单
     *
     * @param orderAgreeDTO 订单同意
     * @return {@link Boolean}
     */
    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean agreeOrderById(OrderAgreeDTO orderAgreeDTO) {
        long sellerId = StpUtil.getLoginIdAsLong();
        //获取签名的字节流
        InputStream inputStream = Base64Util.generateImageStream(orderAgreeDTO.getSellerSignature());
        String sellerSignature = minioUtil.uploadSign(minioConfig.getBucketName(), inputStream, sellerId);
        // 先去订单表查一些基础信息
        ContractOrder contractOrder = contractOrderMapper.selectOne(new LambdaQueryWrapper<ContractOrder>()
                .select(ContractOrder::getBuyerId,
                        ContractOrder::getSellerContactInfoId,
                        ContractOrder::getBuyerContactInfoId,
                        ContractOrder::getBuyerSignature,
                        ContractOrder::getProductSpecies,
                        ContractOrder::getProductVariety,
                        ContractOrder::getUnitPrice,
                        ContractOrder::getOrderWeight)
                .eq(ContractOrder::getId,orderAgreeDTO.getId()));
        //卖方的地址信息
        Long sellerContactInfoId = contractOrder.getSellerContactInfoId();
        Address sellerAddressInfo = addressMapper.selectOne(new LambdaQueryWrapper<Address>()
                .select(Address::getConsignee, Address::getLocation, Address::getDetailedAddress, Address::getPhone)
                .eq(Address::getId, sellerContactInfoId));

        //买方的地址信息
        Long buyerContactInfoId = contractOrder.getBuyerContactInfoId();
        Address buyerAddressInfo = addressMapper.selectOne(new LambdaQueryWrapper<Address>()
                .select(Address::getConsignee, Address::getLocation, Address::getDetailedAddress, Address::getPhone)
                .eq(Address::getId, buyerContactInfoId));
        //计算总价
        BigDecimal totalPrice = DecimalUtils.multiply(contractOrder.getUnitPrice(), contractOrder.getOrderWeight());
        String totalAmount = DecimalUtils.bigDecimalToString(totalPrice);
        LocalDateTime now = LocalDateTime.now();
        int year = now.getYear();
        int monthValue = now.getMonthValue();
        int dayOfMonth = now.getDayOfMonth();

        //组装一下两个签名的map
        Map<String, String> map = new HashMap<>(2);
        map.put("SignatureA",contractOrder.getBuyerSignature());
        map.put("SignatureB",sellerSignature);

        //将上面的数据转换成pdfData
        PdfData pdfData = OrderConvert.INSTANCE.toPdfData(contractOrder, sellerAddressInfo, buyerAddressInfo, totalPrice, totalAmount, year, monthValue, dayOfMonth);
        InputStream pdfStream = PDFUtils.createPDF(Constants.ORDER_URL, pdfData, map, true);
        String orderPath = minioUtil.uploadOrder(minioConfig.getBucketName(), pdfStream, sellerId, contractOrder.getBuyerId());
        return contractOrderMapper.update(null,new LambdaUpdateWrapper<ContractOrder>()
                .set(ContractOrder::getSellerSignature,sellerSignature)
                .set(ContractOrder::getContractUrl,orderPath)
                .set(ContractOrder::getOrderStatus,OrderType.SIGNED.getValue())
                .eq(ContractOrder::getSellerId,sellerId)
                .eq(ContractOrder::getId,orderAgreeDTO.getId())) > 0;
    }




}
